package person.wend.javalearnexample.map;

import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;

public class MapMethodsExample {
    public static void main(String[] args) {
        // Java8MapMethodTest();
        Java9MapMethodsTest();

    }

    /**
     * Java 9中Map接口新增的方法示例
     */
    private static void Java9MapMethodsTest() {

        // 1. Map.of方法示例

        // 创建一个包含0个映射关系的不可变映射（空映射）
        Map<String, Integer> emptyMap = Map.of();
        System.out.println("Empty Map: " + emptyMap);

        // 创建一个包含1个映射关系的不可变映射，键为"one"，值为1
        Map<String, Integer> singleEntryMap = Map.of("one", 1);
        System.out.println("Single Entry Map: " + singleEntryMap);

        // 创建一个包含2个映射关系的不可变映射，注意重复键会抛出异常，这里键分别为"two"、"three"，值为2、3
        try {
            Map<String, Integer> twoEntriesMap = Map.of("two", 2, "two", 3);
            System.out.println("Two Entries Map: " + twoEntriesMap);
        } catch (IllegalArgumentException e) {
            System.out.println("Caught IllegalArgumentException for duplicate key: " + e.getMessage());
        }

        // 创建一个包含多个（这里以3个为例）映射关系的不可变映射，键值分别为"four":4, "five":5, "six":6
        Map<String, Integer> multipleEntriesMap = Map.of("four", 4, "five", 5, "six", 6);
        System.out.println("Multiple Entries Map: " + multipleEntriesMap);

        // 2. Map.ofEntries方法示例

        // 先使用Map.entry方法创建多个Entry实例，模拟给定的条目
        Map.Entry<String, Integer> entry1 = Map.entry("seven", 7);
        Map.Entry<String, Integer> entry2 = Map.entry("eight", 8);

        // 使用ofEntries方法基于创建的Entry实例构建不可变映射
        Map<String, Integer> entriesMap = Map.ofEntries(entry1, entry2);
        System.out.println("Map created by ofEntries: " + entriesMap);

        // 3. Map.entry方法示例

        // 创建一个不可变的Entry实例，键为"nine"，值为9
        Map.Entry<String, Integer> newEntry = Map.entry("nine", 9);
        System.out.println("Created Entry: " + newEntry);

        // 注意，尝试创建键或值为null的Entry会抛出NullPointerException，以下代码会报错，注释掉仅作示意
        // Entry<String, Integer> nullEntry = Map.entry(null, 10);

        // 4. Map.copyOf方法示例

        // 创建一个普通的可变映射（这里用HashMap举例）
        java.util.HashMap<String, Integer> mutableMap = new java.util.HashMap<>();
        mutableMap.put("ten", 10);

        // 使用copyOf方法将可变映射转换为不可变映射，注意原映射不能有null键或值，这里符合要求
        Map<String, Integer> copiedMap = Map.copyOf(mutableMap);
        System.out.println("Copied Map: " + copiedMap);

        // 尝试修改原可变映射，添加新的键值对
        mutableMap.put("eleven", 11);

        // 再次查看不可变映射，不会反映原可变映射后续的修改
        System.out.println("Copied Map after modifying original mutable map: " + copiedMap);

        // 创建一个本身就是不可变映射（这里利用之前创建的entriesMap）
        Map<String, Integer> immutableMap = Map.ofEntries(Map.entry("twelve", 12));

        // 对不可变映射使用copyOf方法，通常不会创建副本，返回原映射
        Map<String, Integer> copiedImmutableMap = Map.copyOf(immutableMap);
        System.out.println("Copied Immutable Map (should be the same as original): " + copiedImmutableMap);

    }

    /**
     * Java 8中Map接口新增的方法示例
     */
    private static void Java8MapMethodTest() {
        // 创建一个HashMap实例，这里使用Map接口来引用它，方便后续切换不同的Map实现类
        Map<String, Integer> map = new HashMap<>();

        // 1. getOrDefault方法示例
        map.put("key1", 10);
        // 使用getOrDefault获取"key1"对应的值，由于存在该键的映射，返回映射的值10
        Integer value1 = map.getOrDefault("key1", 5);
        System.out.println("getOrDefault for key1: " + value1);
        // 使用getOrDefault获取"key2"对应的值，不存在该键的映射，返回默认值5
        Integer value2 = map.getOrDefault("key2", 5);
        System.out.println("getOrDefault for key2: " + value2);

        // 2. forEach方法示例
        // 使用forEach遍历map中的每个条目，并打印键值对信息
        map.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value));
        try {
            // 故意在迭代过程中通过remove方法移除一个条目，会触发ConcurrentModificationException异常
            map.forEach((key, value) -> {
                if ("key1".equals(key)) {
                    map.remove(key);
                }
            });
        } catch (ConcurrentModificationException e) {
            System.out.println("Caught ConcurrentModificationException as expected: " + e.getMessage());
        }

        // 3. replaceAll方法示例
        Map<String, Integer> mapToReplaceAll = new HashMap<>();
        mapToReplaceAll.put("key3", 3);
        mapToReplaceAll.put("key4", 4);
        // 使用replaceAll方法将每个条目的值替换为原来值的两倍
        mapToReplaceAll.replaceAll((key, oldValue) -> oldValue * 2);
        System.out.println("After replaceAll: " + mapToReplaceAll);

        // 4. putIfAbsent方法示例
        Map<String, Integer> mapForPutIfAbsent = new HashMap<>();
        mapForPutIfAbsent.put("key5", 5);
        // 对于已经存在的"key5"键，putIfAbsent不会改变其值，返回已有的值5
        Integer existingValue = mapForPutIfAbsent.putIfAbsent("key5", 6);
        System.out.println("putIfAbsent for existing key5: " + existingValue);
        // 对于不存在的"key6"键，putIfAbsent会添加新的键值对，并返回null
        Integer newKeyValue = mapForPutIfAbsent.putIfAbsent("key6", 6);
        System.out.println("putIfAbsent for new key6: " + newKeyValue);
        System.out.println("Map after putIfAbsent operations: " + mapForPutIfAbsent);

        // 5. replace方法示例
        Map<String, Integer> mapForReplace = new HashMap<>();
        mapForReplace.put("key7", 7);
        // 对于存在的"key7"键，replace会替换其值，并返回旧值7
        Integer replacedValue = mapForReplace.replace("key7", 8);
        System.out.println("replace for existing key7: " + replacedValue);
        // 对于不存在的"key8"键，replace返回null
        Integer nonExistentReplacedValue = mapForReplace.replace("key8", 9);
        System.out.println("replace for non-existent key8: " + nonExistentReplacedValue);
        System.out.println("Map after replace operations: " + mapForReplace);

        // 6. computeIfAbsent方法示例
        Map<String, String> mapForComputeIfAbsent = new HashMap<>();
        // 对于不存在的"key9"键，使用computeIfAbsent通过给定函数计算值并添加键值对，返回计算后的值"ComputedValue"
        String computedValue = mapForComputeIfAbsent.computeIfAbsent("key9", k -> "ComputedValue");
        System.out.println("computeIfAbsent for new key9: " + computedValue);
        // 对于已经存在的"key10"键（假设已存在，这里示例代码没添加，实际可自行添加测试），computeIfAbsent不会改变其值，返回已有的值
        String existingComputedValue = mapForComputeIfAbsent.computeIfAbsent("key10", k -> "AnotherComputedValue");
        System.out.println("computeIfAbsent for existing key10: " + existingComputedValue);
        System.out.println("Map after computeIfAbsent operations: " + mapForComputeIfAbsent);

        // 7. computeIfPresent方法示例
        Map<String, Integer> mapForComputeIfPresent = new HashMap<>();
        mapForComputeIfPresent.put("key11", 11);
        // 对于存在且值非null的"key11"键，使用computeIfPresent根据键和旧值计算新值并替换，返回新值12
        Integer computedIfPresentValue = mapForComputeIfPresent.computeIfPresent("key11", (k, v) -> v + 1);
        System.out.println("computeIfPresent for existing key11: " + computedIfPresentValue);
        // 对于不存在的"key12"键，computeIfPresent返回null
        Integer nonExistentComputeIfPresentValue = mapForComputeIfPresent.computeIfPresent("key12", (k, v) -> v + 1);
        System.out.println("computeIfPresent for non-existent key12: " + nonExistentComputeIfPresentValue);
        System.out.println("Map after computeIfPresent operations: " + mapForComputeIfPresent);

        // 8. compute方法示例
        Map<String, Integer> mapForCompute = new HashMap<>();
        mapForCompute.put("key13", 13);
        // 对于存在的"key13"键，使用compute根据键和旧值计算新值并替换，返回新值14
        Integer computedNewValue = mapForCompute.compute("key13", (k, v) -> v + 1);
        System.out.println("compute for existing key13: " + computedNewValue);
        // 对于不存在的"key14"键，compute根据计算结果添加新的键值对（这里示例计算返回固定值15），返回新值15
        Integer computedNewValueForAbsentKey = mapForCompute.compute("key14", (k, v) -> 15);
        System.out.println("compute for absent key14: " + computedNewValueForAbsentKey);
        System.out.println("Map after compute operations: " + mapForCompute);

        // 9. merge方法示例
        Map<String, String> mapForMerge = new HashMap<>();
        mapForMerge.put("key15", "Value1");
        // 对于已存在的"key15"键，使用merge根据重映射函数合并值，返回新值"Value1New"
        String mergedValue = mapForMerge.merge("key15", "New", (oldValue, newValue) -> oldValue + "New");
        System.out.println("merge for existing key15: " + mergedValue);
        // 对于不存在的"key16"键，merge添加新的键值对，返回给定的非null值"NewValue"
        String mergedValueForNewKey = mapForMerge.merge("key16", "NewValue", (oldValue, newValue) -> oldValue + newValue);
        System.out.println("merge for new key16: " + mergedValueForNewKey);
        System.out.println("Map after merge operations: " + mapForMerge);
    }
}